﻿using Furion;
using Furion.DataEncryption;
using Furion.InstantMessaging;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Caching.Distributed;
using SignalRHubs.Application.Extensions;
using SignalRHubs.Application.Hubs.Dto;
using SignalRHubs.Application.Hubs.Entity;
using SignalRHubs.Application.Hubs.Enum;
using SignalRHubs.Application.Hubs.Request;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UAParser;

namespace SignalRHubs.Application.Hubs
{
    [MapHub("/hubs/chatroomhub")]
    public class ChatRoomHub : Hub<IChatRoomClient>
    {
        private readonly IDistributedCache _cache;
        public ChatRoomHub(IDistributedCache cache)
        {
            _cache = cache;
        }
        /// <summary>
        /// 连接
        /// </summary>
        /// <returns></returns>
        public override async Task OnConnectedAsync()
        {
            await Task.Run(() =>
                {
                    //var client = Parser.GetDefault().Parse(Context.GetHttpContext().Request.Headers["User-Agent"]);
                    //var loginBrowser = client.UA.Family + client.UA.Major;
                    //var loginOs = client.OS.Family + client.OS.Major;
                    //var ip = Context.GetHttpContext().Connection.RemoteIpAddress;
                    //if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(account))
                    //{
                    //    //禁止连接
                    //    Context.Abort();
                    //}
                    //this.Clients.Groups()
                });
        }


        public override async Task<Task> OnDisconnectedAsync(Exception exception)
        {
            var key = $"{ConstKey.在线用户}{Context.ConnectionId}";
            var user = await _cache.GetObjectAsync<ChatUser>(key);

            await _cache.RemoveAsync(key);


            var users = (await _cache.GetObjectAsync<List<ChatUserDto>>($"{ConstKey.群在线用户列表}{user.CurrentGroup}")) ?? new List<ChatUserDto>();
            users = users.Where(x => x.Id != user.Id).ToList();
            await NotifyGroupUserList(user.CurrentGroup, users);       

            return base.OnDisconnectedAsync(exception);
        }



        #region 定义客户端 invoke 的函数

        public async Task<dynamic> TokenLogin(string token)
        {
            var user = await GetUser(token);

            return await LoginCompleted(user);


            //user.ConnectionId = Context.ConnectionId;
            //user.LastLoginIp = GetIp();
            //user.LastLoginTime = DateTimeOffset.Now;

            //var key = $"{ConstKey.用户列表}{user.Account}";
            //await _cache.SetObjectAsync(key, user);

            //// 生成 token
            //var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
            //{
            //    //{ "UserId", user.Id },  // 存储Id
            //    {  ClaimConst.ACCOUNT,user.Account}, // 存储用户名
            //    //{ "NickName",user.NickName }, // 存储用户名
            //});

            //var dto = user.Adapt<ChatUserDto>();
            //dto.Token = accessToken;
            //return dto;
        }


        /// <summary>
        /// 用户注册
        /// </summary>
        /// <param name="json"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<dynamic> Register(string json, string token)
        {
            var request = json.ToObject<RegistRequest>();
            var key = $"{ConstKey.用户列表}{request.Account}";
            var data = await _cache.GetStringAsync(key);
            if (!string.IsNullOrWhiteSpace(data))
            {
                await Clients.Client(Context.ConnectionId).ReciveMessage(new ChatRoomMessage
                {
                    Message = $"用户名已存在",
                    ToConnectionId = Context.ConnectionId,
                    Type = MessageType.提示消息
                });
                return null;
            }

            var user = request.Adapt<ChatUser>();
            return await LoginCompleted(user);


            //user.LastLoginIp = GetIp();
            //user.LastLoginTime = DateTimeOffset.Now;
            //user.Id = Context.ConnectionId;
            //await _cache.SetObjectAsync(key, user);


            //// 生成 token
            //var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
            //{
            //    //{ "UserId", user.Id },  // 存储Id
            //    {  ClaimConst.ACCOUNT,user.Account}, // 存储用户名
            //    //{ "NickName",user.NickName }, // 存储用户名
            //});

            //var dto = user.Adapt<ChatUserDto>();
            //dto.Token = accessToken;
            //return dto;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="json"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<dynamic> Login(string json, string token)
        {
            var request = json.ToObject<LoginRequest>();
            var key = $"{ConstKey.用户列表}{request.Account}";
            var user = await _cache.GetObjectAsync<ChatUser>(key);
            if (user == null || user.Password != request.Password)
            {
                await Clients.Client(Context.ConnectionId).ReciveMessage(new ChatRoomMessage
                {
                    Message = $"账号或者密码错误",
                    ToConnectionId = Context.ConnectionId,
                    Type = MessageType.提示消息
                });
                return null;
            }


            return await LoginCompleted(user);

        }

        public async Task<ChatUser> CheckToken(string token)
        {
            return await GetUser(token);
        }

        public async Task<ChatGroup> CreateGroup(string json, string token)
        {
            var request = json.ToObject<CreateGroupRequest>();
            var key = $"{ConstKey.群列表}{request.GroupName}";
            var group = await _cache.GetObjectAsync<ChatGroup>(key);
            if (group != null)
            {
                await Clients.Client(Context.ConnectionId).ReciveMessage(new ChatRoomMessage
                {
                    Message = $"群名已存在",
                    ToConnectionId = Context.ConnectionId,
                    Type = MessageType.提示消息
                });
                return null;
            }

            var user = await GetUser(token);
            group = request.Adapt<ChatGroup>();
            group.AllowJoin = true;
            group.AdminId = user.Id;
            await _cache.SetObjectAsync(key, group);

            var r = new JoinGroupRequest { GroupName = request.GroupName };
            return await JoinGroup(r.ToJson(), token);

        }

        //public async Task<List<ChatUserDto>> Heartbeat(string json, string token)
        //{
        //    var request = json.ToObject<JoinGroupRequest>();
        //    var user = (await GetUser(token)).Adapt<ChatUserDto>();
        //    var key = $"{ConstKey.群在线用户列表}{request.GroupName}";
        //    var users = (await _cache.GetObjectAsync<List<ChatUserDto>>(key)) ?? new List<ChatUserDto>();
        //    var time = DateTimeOffset.Now.AddMinutes(-3);
        //    //3分钟没心跳  认为掉线
        //    users = users.Where(x => x.Id != user.Id && x.HeartbeatTime > time).ToList();
        //    user.HeartbeatTime = DateTimeOffset.Now;
        //    users.Add(user);
        //    return users;
        //}

        // 加入分组
        public async Task<ChatGroup> JoinGroup(string json, string token)
        {
            var request = json.ToObject<JoinGroupRequest>();
            var user = await GetUser(token);
            var key = $"{ConstKey.群列表}{request.GroupName}";
            var group = await _cache.GetObjectAsync<ChatGroup>(key);
            if (group == null)
            {
                //await Clients.Client(Context.ConnectionId).ReciveMessage(new ChatRoomMessage
                //{
                //    Message = $"群不存在",
                //    ToConnectionId = Context.ConnectionId,
                //    Type = ChatRoomMessage.MessageType.提示消息
                //});
                //return null;

                group = request.Adapt<ChatGroup>();
                group.AllowJoin = true;
                group.AdminId = user.Id;
                await _cache.SetObjectAsync(key, group);

                //var r = new ChatGroup { GroupName = request.GroupName };

            }
            else if (!group.AllowJoin)
            {
                await Clients.Group(request.GroupName).ReciveMessage(new ChatRoomMessage
                {
                    FromGroupId = request.GroupName,
                    Message = $"当前聊天室禁止进入",
                    ToGroupId = request.GroupName,
                    ToConnectionId = Context.ConnectionId,
                    Type = MessageType.提示消息
                });
                return null;
            }
            //加入分组
            await Groups.AddToGroupAsync(Context.ConnectionId, request.GroupName.ToUpper());
            await Clients.Group(request.GroupName).ReciveMessage(new ChatRoomMessage
            {
                FromGroupId = request.GroupName,
                Message = $"欢迎{user.NickName}回来",
                ToGroupId = request.GroupName,
                Type = MessageType.系统消息
            });

            //更新用户信息
            user.CurrentGroup = request.GroupName;
            await _cache.SetObjectAsync($"{ConstKey.用户列表}{user.Account}", user);



            var key2 = $"{ConstKey.群在线用户列表}{request.GroupName}";

            var users = (await _cache.GetObjectAsync<List<ChatUserDto>>(key2)) ?? new List<ChatUserDto>();
            users.Add(user.Adapt<ChatUserDto>());

            await NotifyGroupUserList(request.GroupName, users);

            return new ChatGroup
            {
                AdminId = group.AdminId,
                GroupName = request.GroupName
            };
        }

        //离开分组
        public async Task ExitGroup(string groupId)
        {
            await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupId.ToUpper());
        }


        public async Task SendMessage(string json, string token)
        {
            var request = json.ToObject<SendMessageRequest>();
            var user = (await GetUser(token)).Adapt<ChatUserDto>();

            await Clients.Group(request.ToGroupId).ReciveMessage(new ChatRoomMessage
            {
                Message = request.Message,
                Type = request.Type,
                FromConnectionId = user.ConnectionId,
                ToGroupId = request.ToGroupId,
                FromGroupId = request.FromGroupId,
                ChatUser = user
            });

        }
        #endregion

        private string GetIp()
        {
            return Context.GetHttpContext().Connection.RemoteIpAddress?.ToString();
        }

        private async Task<ChatUser> GetUser(string token)
        {
            var claims = JWTEncryption.ReadJwtToken(token)?.Claims;
            var account = claims.FirstOrDefault(e => e.Type == ClaimConst.ACCOUNT)?.Value;

            var key = $"{ConstKey.用户列表}{account}";
            var user = await _cache.GetObjectAsync<ChatUser>(key);
            return user;

        }

        /// <summary>
        /// 登录成功后 更新用户信息
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private async Task<ChatUserDto> LoginCompleted(ChatUser user)
        {
            var client = Parser.GetDefault().Parse(Context.GetHttpContext().Request.Headers["User-Agent"]);
            var loginBrowser = client.UA.Family + client.UA.Major;
            var loginOs = client.OS.Family + client.OS.Major;
            //var ip = Context.GetHttpContext().Connection.RemoteIpAddress;


            user.LastLoginIp = GetIp();
            user.LastLoginTime = DateTimeOffset.Now;
            user.ConnectionId = Context.ConnectionId;
            user.HeartbeatTime = DateTimeOffset.Now;
            user.UserAgent = $"{loginOs} {loginBrowser}";
            if (string.IsNullOrWhiteSpace(user.Id))
            {
                user.Id = Context.ConnectionId;
            }
            var key = $"{ConstKey.用户列表}{user.Account}";
            await _cache.SetObjectAsync(key, user);

            await _cache.SetObjectAsync($"{ConstKey.在线用户}{user.ConnectionId}", user);

            // 生成 token
            var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
            {
                //{ "UserId", user.Id },  // 存储Id
                {  ClaimConst.ACCOUNT,user.Account}, // 存储用户名
                //{ "NickName",user.NickName }, // 存储用户名
            });
            var dto = user.Adapt<ChatUserDto>();
            dto.Token = accessToken;
            return dto;

        }

        private async Task NotifyGroupUserList(string group, List<ChatUserDto> users)
        {
            await _cache.SetObjectAsync($"{ConstKey.群在线用户列表}{group}", users);
            await Clients.Group(group).ReciveMessage(new ChatRoomMessage
            {
                FromGroupId = group,
                Message = users.ToJson(),
                ToGroupId = group,
                Type = MessageType.在线用户
            });

        }

       
    }
}
